package genericity;

import java.util.ArrayList;
import java.util.List;

/**
 *  泛型通配符 <?>: 表示任意类型,如果没有明确,那么就是Object以及任意Java类;
 *
 * 受限泛型
 *
 * 设置上限:   设置泛型的上限范围 如:extends Number 所有number子类可以
 *
 *      声明类:  类名称<泛型标识 extends 类>{}
 *      声明对象: 类名称< ? extends 类> 对象名
 *
 * 设置下限:   设置泛型的下限范围  如: super String 只能接受String以及String的父类。
 *
 *      声明类: 类名称<泛型标识 super 类>{}
 *      声明对象: 类名< ? super 类> 对象名
 */

public class GenericClass1<T> {
    private T var;

    public T getVar() {
        return var;
    }

    public void setVar(T var) {
        this.var = var;
    }

    @Override
    public String toString() {
        return var.toString();
    }

    /**
     * 设置上限方法
     * @param arg
     * @param <K>
     * @return
     */
    public <K extends Number> K test1(K arg) {  //此处泛型只能是数字类型
        System.out.printf("arg:"+arg.toString());
        return arg;
    }

}

/**
 * 不仅仅在使用过程中，也可以在定义类的时候指定泛型上限：
 */
class GenericClass2<T extends Number> {   //此处泛型只能是数字类型
    private T var;

    public T getVar() {
        return var;
    }

    public void setVar(T var) {
        this.var = var;
    }

    @Override
    public String toString() {
        return var.toString();
    }

    /**
     * 设置泛型下限
     * @param list
     */
    public void add(List<? super String> list){
        System.out.println(list.toString());
    }

}


/**
 * 测试上限
 */
class GenericsDemo {

    public static void main(String[] args) {
        GenericClass1<Integer> info1 = new GenericClass1<Integer>();
        GenericClass1<Float> info2 = new GenericClass1<Float>();
        GenericClass1<String> info3 = new GenericClass1<String>();
        info1.setVar(30);  // 设置整数，自动装箱
        info2.setVar(30.1F);  // 设置小数，自动装箱
        info3.setVar("俺是字符串，不能被受限的FUN组装");
        fun(info1);
        fun(info2);
        info1.test1(123);   //上限方法
//        fun(info3);  //受限了，不能调用这个

        GenericClass2<Integer> i1=new GenericClass2();  // 声明Integer的泛型对象
    }

    /**
     * 设置上限     // 只能接收Number及其Number的子类
     */
    public static void fun(GenericClass1<? extends Number> temp) {// 只能接收String或Object类型的泛型
        System.out.println("内容：" + temp);
    }

}

/**
 * 测试下限
 */
class GenericsDemo1 {
    public static void main(String args[]) {
        GenericClass1<String> i1 = new GenericClass1<String>();        // 声明String的泛型对象
        GenericClass1<Object> i2 = new GenericClass1<Object>();        // 声明Object的泛型对象
        i1.setVar("hello");
        i2.setVar(new Object());
        fun1(i1);
        fun1(i2);

        GenericClass2<Integer> test=new GenericClass2();
        List<Integer> list =new ArrayList<>();
        list.add(2);
        List<Object> list1=new ArrayList<>();
        list1.add("haha");
//        test.add(list);   // //受限了，不能调用这个
        test.add(list1);   // //受限了，不能调用这个

    }

    /**
     * 设置下限     // 只能接受String及父类object
     */
    public static void fun1(GenericClass1<? super String> temp) {    // 只能接收String或Object类型的泛型
        System.out.println(temp + "、");
    }
}

/**
 * 泛型数组
 */
class GenericsDemo2{
    public static void main(String args[]){
        Integer i[] = fun1(1,2,3,4,5,6) ;    // 返回泛型数组
        fun2(i) ;
    }

    public static <T> T[] fun1(T...arg){    // 接收可变参数
        return arg ;            // 返回泛型数组
    }

    public static <T> void fun2(T[] param) {    // 输出
        System.out.print("接收泛型数组：");
        for (T t : param) {
            System.out.print(t + "、");
        }
    }
}


/**
 *  泛型嵌套
 */
class Info<T, V> {        // 接收两个泛型类型
    private T var;
    private V value;

    public Info(T var, V value) {
        this.setVar(var);
        this.setValue(value);
    }

    public void setVar(T var) {
        this.var = var;
    }

    public void setValue(V value) {
        this.value = value;
    }

    public T getVar() {
        return this.var;
    }

    public V getValue() {
        return this.value;
    }
}

class Demo<S> {
    private S info;

    public Demo(S info) {
        this.setInfo(info);
    }

    public void setInfo(S info) {
        this.info = info;
    }

    public S getInfo() {
        return this.info;
    }
}

class GenericsDemo3 {
    public static void main(String args[]) {
        Demo<Info<String, Integer>> d = null;        // 将Info作为Demo的泛型类型
        Info<String, Integer> i = null;    // Info指定两个泛型类型
        i = new Info<String, Integer>("李兴华", 30);     // 实例化Info对象
        d = new Demo<Info<String, Integer>>(i);    // 在Demo类中设置Info类的对象
        System.out.println("内容一：" + d.getInfo().getVar());
        System.out.println("内容二：" + d.getInfo().getValue());
    }
}